﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Web.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Ext.Direct.Mvc
{
    public class DirectMethodInvoker : ControllerActionInvoker
    {
        protected override IDictionary<string, object> GetParameterValues(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
            Dictionary<string, object> parametersDict = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
            ParameterDescriptor[] parameterDescriptors = actionDescriptor.GetParameters();
            DirectRequest directRequest = controllerContext.HttpContext.Items[DirectRequest.DirectRequestKey] as DirectRequest;
            CultureInfo invariantCulture = CultureInfo.InvariantCulture;
            IDictionary<string, ValueProviderResult> valueProvider = new Dictionary<string, ValueProviderResult>();

            if (!directRequest.IsForm) {
                object[] data = directRequest.Data;

                for (int i = 0; i < parameterDescriptors.Length; i++) {
                    string key = parameterDescriptors[i].ParameterName;
                    object rawValue = data[i];

                    if (rawValue is JObject && parameterDescriptors[i].ParameterType != typeof(JObject)) {
                        rawValue = JsonConvert.DeserializeObject(rawValue.ToString(), parameterDescriptors[i].ParameterType);
                    }

                    string attemptedValue = Convert.ToString(rawValue, invariantCulture);
                    valueProvider.Add(key, new ValueProviderResult(rawValue, attemptedValue, invariantCulture));
                }

                controllerContext.Controller.ValueProvider = valueProvider;
            }

            foreach (ParameterDescriptor parameterDescriptor in parameterDescriptors) {
                parametersDict[parameterDescriptor.ParameterName] = GetParameterValue(controllerContext, parameterDescriptor);
            }
            return parametersDict;
        }
    }
}
